/*
 * @Descripttion: 实现DOM-diff深度对比
 * @Author: lukasavage
 * @Date: 2021-12-29 21:04:53
 * @LastEditors: lukasavage
 * @LastEditTime: 2021-12-29 21:18:24
 */

import { compareTwoVdom, findDOM } from './react-dom4';
/* ①、首先定义一个更新队列 */
export let updateQueue = {
	isBatchingUpdate: false,
	updaters: new Set(),
	batchUpdate() {
		for (const iterator of this.updaters) {
			iterator.updateComponent();
		}
		this.isBatchingUpdate = false;
		this.updaters.clear();
	},
};

function shouldUpdate(classInstance, nextProps, newState) {
	let willUpdate = true;
	if (
		classInstance.shouldComponentUpdate &&
		!classInstance.shouldComponentUpdate(nextProps, newState)
	) {
		willUpdate = false;
	}

	if (willUpdate && classInstance.componentWillUpdate) {
		classInstance.componentWillUpdate();
	}

	classInstance.state = newState;

    // 如果有新属性的话，更改属性
    if(nextProps) classInstance.props = nextProps;

	if (willUpdate) {
		classInstance.forceUpdate();
	}
}
class Updater {
	constructor(classInstance) {
		this.classInstance = classInstance;
		this.pendingState = [];
		this.callbacks = [];
	}
	addState(partialState, callback) {
		this.pendingState.push(partialState);
		if (callback && typeof callback === 'function') {
			this.callbacks.push(callback);
		}
		this.emitUpdate();
	}
	emitUpdate(nextProps) {
		this.nextProps = nextProps;
		if (updateQueue.isBatchingUpdate) {
			updateQueue.updaters.add(this);
		} else {
			this.updateComponent();
		}
	}
	updateComponent() {
		const { classInstance, pendingState, nextProps, callbacks } = this;
		if (nextProps || pendingState.length) {
			shouldUpdate(classInstance, nextProps, this.getState());
		}
		if (callbacks.length) {
			callbacks.forEach(item => item());
			callbacks.length = 0;
		}
	}
	getState() {
		let newState;
		const {
			classInstance: { state },
			pendingState,
		} = this;
		pendingState.forEach(item => {
			if (typeof item === 'function') {
				item = item(state);
			}
			newState = { ...state, ...item };
		});
		return newState;
	}
}
export class Component {
	static isReactComponent = true;
	constructor(props) {
		this.props = props;
		this.state = {};
		this.updater = new Updater(this);
	}
	setState(partialState) {
		this.updater.addState(partialState);
	}
	forceUpdate() {
		const oldRenderVdom = this.oldRenderVdom;
		const oldDOM = findDOM(oldRenderVdom);
		const newVdom = this.render();
		compareTwoVdom(oldDOM.parentNode, oldRenderVdom, newVdom);
		this.oldRenderVdom = newVdom;
		if (this.componentDidUpdate) {
			this.componentDidUpdate(this.props, this.state);
		}
	}
}
